package com.atlige.gzmall.product;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

/**
 * 1、整合mybatis-plus
 *  1）导入依赖
 *  2）配置
 *      - 配置数据源
 *      - 配置mybatis-plus
 *          - 使用@MapperScan
 *          - 告诉MyBatis-Plus，sql映射文件的位置
 * 2、逻辑删除
 *  1）配置全局的逻辑删除规则(省略)
 *  2）配置逻辑删除的组件（3.1以后省略）
 *  3）给bean加上逻辑删除注解@TableLogic
 *
 * 3、后端校验：JSR303
 *  1）给bean添加校验注解 : package javax.validation.constraints，并定义自己的message提示
 *  2）开启校验功能 @Valid
 *  3）给校验的bean后紧跟一个BindingResult，就可以获取道校验结果
 *  4）分组校验(多场景的复杂校验)
 *     - @NotBlank(message = "品牌名不能为空", groups = {UpdateGroup.class, AddGroup.class})
 *     - 给校验注解标注什么情况下需要校验
 *     - @Validated(AddGroup.class)
 *     - 默认没有指定分组的校验注解@NotBlank，在分组校验情况@Validated({AddGroup.class})下不生效
 *  5）自定义校验
 *     - 编写一个自定义校验注解
 *     - 编写一个自定义的校验器
 *     - 关联自定义的校验器和自定义的校验注解
 *
 * 4、统一的异常处理
 *      @ControllerAdvice
 * 5、模板引擎
 *  1）thymeleaf-starter：关闭缓存
 *  2）静态资源放在static文件夹下，页面放在templates下，可以直接访问、
 *      SpringBoot访问项目时，默认会找index
 *  3) 页面修改不重启服务器实时更新
 *      - 引入dev-tools
 *      - 编译项目或文件 ctrl+F9(一定要关闭缓存)
 *
 * 6、整合redis
 *  - 引入spring-boot-starter-data-redis
 *  - 简单配置redis的相关信息
 *  - 使用SpringBoot自动配置好的StringRedisTemplate来操作redis
 * 7、整合redisson作为分布式锁等功能框架
 *  1）引入依赖
 *      <dependency>
 *          <groupId>org.redisson</groupId>
 *          <artifactId>redisson</artifactId>
 *          <version>3.15.2</version>
 *      </dependency>
 *  2）配置redisson
 *      MyRedissonConfig给容器中注册一个RedissonClient组件
 *  3）使用
 *      参考文档使用
 *  8、整合SpringCache简化开发
 *      1）引入依赖
 *          <dependency>
 *             <groupId>org.springframework.boot</groupId>
 *             <artifactId>spring-boot-starter-cache</artifactId>
 *         </dependency>
 *      2）写配置
 *          （1）自动配置了哪些？
 *                CacheAutoConfiguration 会导入 RedisCacheConfiguration
 *                自动配好了缓存管理器 RedisCacheManager
 *          （2）配置使用redis作为缓存
 *       3）测试使用注解
 *          @Cacheable: Triggers cache population. 触发将数据保存到缓存的操作
 *          @CacheEvict: Triggers cache eviction.  触发将数据从缓存删除的操作
 *          @CachePut: Updates the cache without interfering with the method execution. 在不干扰方法执行的情况下更新缓存。
 *          @Caching: Regroups multiple cache operations to be applied on a method.组合以上多个操作
 *          @CacheConfig: Shares some common cache-related settings at class-level.在类级别共享缓存的相同配置
 *          1）开启缓存 @EnableCaching
 *          2) 只需要使用注解就能完成缓存操作
 *
 *
 *     原理：
 *           CacheAutoConfiguration ---> RedisCacheConfiguration ---> 自动配置了RedisCacheManager ---> 初始化所有缓存
 * Spring-Cache的不足:
 *  1)读模式:
 *      缓存穿透: 查询一个null数据 解决方案: cache-null-values = true
 *      缓存击穿: 大量并发进来同时查询一个正好过期的数据. 解决方案: 加分布式锁,默认不加锁@Cacheable(sync = true)加锁
 *      缓存雪崩: 大量的key同时过期. 解决: 加随机时间 time-to-live: 36000
 *  2)写模式:(缓存与数据库一样)
 *      读写加锁
 *      引入Canal,感知到MySQL的更新去更新数据库
 *      读多写多,直接去数据库查询就行
 *  总结:
 *      常规数据(读多写少, 即时性, 一致性要求不高的数据) : 完全可以使用spring-cache; 写模式(只要缓存数据有过期时间就足够了)
 *      特殊数据: 特殊设计
 *  原理:
 *      CacheManager(RedisCacheManager) -> Cache(RedisCache) -> Cache负责缓存的读写
 */
@MapperScan("com.atlige.gzmall.product.dao")
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.atlige.gzmall.product.feign")
@EnableRedisHttpSession
public class GzmallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GzmallProductApplication.class, args);
    }

}
